/*
 * PGN_Reader : A simple pgn reader for chess games.
 * Copyright (C) 2011 Laurent BERNABE
 * 
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 */
package com.gmail.bernabe.laurent.java_swing.pgn_reader.processing.libraries_adapters;

import ictk.boardgame.AmbiguousMoveException;
import ictk.boardgame.History;
import ictk.boardgame.IllegalMoveException;
import ictk.boardgame.chess.ChessBoard;
import ictk.boardgame.chess.ChessGame;
import ictk.boardgame.chess.Square;
import ictk.boardgame.chess.io.PGNReader;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;

import com.gmail.bernabe.laurent.java_swing.pgn_reader.gui.BoardCell;
import com.gmail.bernabe.laurent.java_swing.pgn_reader.processing.ChessLibraryAdapter;
import com.gmail.bernabe.laurent.java_swing.pgn_reader.processing.ChessMove;
import com.gmail.bernabe.laurent.java_swing.pgn_reader.processing.ChessMove.ChessMoveBuilder;
import com.gmail.bernabe.laurent.java_swing.pgn_reader.processing.ChessPiece;
import com.gmail.bernabe.laurent.java_swing.pgn_reader.processing.PieceColor;
import com.gmail.bernabe.laurent.java_swing.pgn_reader.processing.PieceForce;

/**
 * Adapter for the ictk (0.2.0) library.
 * @author laurent-bernabe
 *
 */
public class ICTKLibraryAdapter implements ChessLibraryAdapter {

	@Override
	public ChessPiece getPieceAt(BoardCell cellCoords) {
		ChessBoard board = (ChessBoard) currentChessGame.getBoard();
		ictk.boardgame.chess.ChessPiece ictkPiece = board.getSquare(cellCoords.getFile()+1, cellCoords.getRank()+1).getOccupant();
		return convertToGenericChessPiece(ictkPiece);
	}
	
	@Override
	public void loadPGN(File pgnFile) throws FileNotFoundException, IllegalMoveException, AmbiguousMoveException {
		registeredGames.clear();
		FileReader fileReader = new FileReader(pgnFile);
		PGNReader pgnReader = new PGNReader(fileReader);
		while (true) {
			try {
				registeredGames.add((ChessGame) pgnReader.readGame());
			} catch (IllegalMoveException e) {
				tryToClosePGNReader(pgnReader);
				throw e;
			} catch (AmbiguousMoveException e) {
				tryToClosePGNReader(pgnReader);
				throw e;
			} catch (IOException e) {
				tryToClosePGNReader(pgnReader);
				break;
			}
		}
	}

	@Override
	public void gotoStart() {
		currentChessGame.getHistory().rewind();
	}

	@Override
	public void gotoEnd() {
		currentChessGame.getHistory().goToEnd();
	}

	@Override
	public void playNextHalfMove() {
		currentChessGame.getHistory().next();
	}

	@Override
	public void goBackOneHalfMove() {
		currentChessGame.getHistory().prev();
	}
	
	@Override
	public void loadGame(int gameIndexInCollection) {
		int index = gameIndexInCollection < registeredGames.size() ? gameIndexInCollection : 0;
		setGame(registeredGames.get(index));
	}
	
	private ChessPiece convertToGenericChessPiece(ictk.boardgame.chess.ChessPiece originalPiece){
		if (originalPiece == null)
			return null;
		PieceColor color = originalPiece.isBlack() ? PieceColor.black : PieceColor.white;
		PieceForce force;
		if (originalPiece.isPawn())
			force = PieceForce.pawn;
		else if (originalPiece.isKnight())
			force = PieceForce.knight;
		else if (originalPiece.isBishop())
			force = PieceForce.bishop;
		else if (originalPiece.isRook())
			force = PieceForce.rook;
		else if (originalPiece.isQueen())
			force = PieceForce.queen;
		else if (originalPiece.isKing())
			force = PieceForce.king;
		else
			throw new IllegalArgumentException("Original piece has not a known force !!!");
		return new ChessPiece(force, color);
	}
	
	/**
	 * Sets the used ictk chess game.
	 * @param game
	 */
	private void setGame(ChessGame game){
		this.currentChessGame = game;
		getMovesFromGame(game);
	}
	
	private void getMovesFromGame(ChessGame game) {
		moves.clear();
		History gameHistory = game.getHistory();
		ictk.boardgame.chess.ChessMove currentMove = (ictk.boardgame.chess.ChessMove) gameHistory.getFirst();
		
		while (currentMove != null){
			Square moveOrigin = currentMove.getOrigin();
			Square moveDestination = currentMove.getDestination();
			ictk.boardgame.chess.ChessPiece capturedPiece = currentMove.getCasualty();
			
			ChessMoveBuilder chessMoveBuilder = new ChessMoveBuilder();
			chessMoveBuilder.setStartCell(new BoardCell(moveOrigin.getFile() - 1, moveOrigin.getRank() - 1));
			chessMoveBuilder.setEndCell(new BoardCell(moveDestination.getFile() - 1, moveDestination.getRank() - 1));
			chessMoveBuilder.setCapturedPieceValue(convertToGenericChessPiece(capturedPiece));
			chessMoveBuilder.setCapturedPieceCell(new BoardCell(capturedPiece.getSquare().getFile()-1, capturedPiece.getSquare().getRank()-1));
			chessMoveBuilder.setPromotedPiece(convertToGenericChessPiece(currentMove.getPromotion()));
			
			moves.add(chessMoveBuilder.build());
			currentMove = (ictk.boardgame.chess.ChessMove) currentMove.getNext();
		}
	}
	
	private void tryToClosePGNReader(PGNReader pgnReader) {
		try {
			pgnReader.close();
		} catch (IOException e1) {
			e1.printStackTrace();
		}
	}

	private ChessGame currentChessGame;
	private ArrayList<ChessMove> moves;
	private ArrayList<ChessGame> registeredGames;
	
}
